using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using System.IO;

namespace Ramparts
{
    public class TileGrid
    {
        #region Member Data
        private int[][] grid;
        private GraphicsDeviceManager graphics;
        public int gridWidth;
        public int gridHeight;
        private Vector2 worldOffset;
        private Rectangle visibleTiles;
        private SceneManager sceneManager;

        public Dictionary<int, AnimatedTile> animatedTiles;

        private Vector2 scaleValue;
        private Vector2 displaySize;
        private Color layerColor = Color.White;
        public int cellWidth;
        public int cellHeight;
       
        private SpriteSheet currentSheet;
        public SpriteSheet isometricSheet;
        private SpriteSheet twoDimensionalSheet;
        #endregion


        #region Methods

        /// <summary>
        /// Builds a tile grid based on an input configuration file
        /// </summary>
        /// <param name="sFileName">Grid layout configuration file</param>
        public void loadTileGridFromFile(string sFileName)
        {
            StreamReader srReader = null;
            string textRow;
            int row = 0;
            int col = 0;

            try
            {
                /* Open the file */
                srReader = File.OpenText(sFileName);

                /* Read the height and width parameters from the file */
                gridWidth = Convert.ToInt32(srReader.ReadLine());
                gridHeight = Convert.ToInt32(srReader.ReadLine());

                /* Read the remaining config data for this grid */
                while (!srReader.EndOfStream)
                {
                    textRow = srReader.ReadLine();
                    string[] strValues = textRow.Split();

                    foreach (string item in strValues)
                    {
                        grid[col][row] = Convert.ToInt32(item);
                        col = col + 1;
                    }
                    row += 1;
                    col = 0;
                }
            }
            catch (Exception x)
            {
                Console.WriteLine(x.ToString());
            }
            finally
            {
                if (srReader != null)
                {
                    srReader.Close();
                }
            }
        }


        public int getGridValueByCoordinates(int x, int y)
        {
            Vector2 gridCoord = onTile(new Vector2(x,y));
            return getGridValueAt(gridCoord);
        }

        /// <summary>
        /// Returns the grid position for a given V2 vector
        /// </summary>
        /// <param name="position">Screen position as vector</param>
        /// <returns>Grid value as integer</returns>
        public int getGridValueAt(Vector2 position)
        {
            if (position.X < gridWidth  &&
                position.X >= 0 &&
                position.Y < gridHeight &&
                position.Y >= 0)
            {
                return grid[(int)position.X][(int)position.Y];
            }
            else
            {
                return -1;
            }
        }

        public int getGridValueAt(int row, int col)
        {
            if (row < gridWidth   &&
                row >= 0 &&
                col < gridHeight   &&
                col >= 0)
            {
                return grid[row][col];
            }
            else
            {
                return -1;
            }
        }

        

        /// <summary>
        /// Initializes a tile grid set as determined by the parameter data
        /// </summary>
        /// <param name="tileWidth">Width of tiles as int</param>
        /// <param name="tileHeight">Height of tiles as int</param>
        /// <param name="numXTiles">Number of tiles (x direction) as int</param>
        /// <param name="numYTiles">Number of tiles (y direction) as int</param>
        /// <param name="offset">Camera offset position as int</param>
        /// <param name="tileSheet">Tile spritesheet</param>
        /// <param name="graphicsComponent">Current graphics component</param>
        /// <param name="sceneManager">Current Scene manager</param>
        public TileGrid(int tileWidth, int tileHeight, int numXTiles, int numYTiles,
            Vector2 offset, SpriteSheet tileSheet,
            GraphicsDeviceManager graphicsComponent, SceneManager sceneManager)
        {
            /* Ensure a graphics component exists */
            if (graphicsComponent == null)
            {
                throw new ArgumentNullException("graphicsComponent");
            }


            animatedTiles = new Dictionary<int, AnimatedTile>();

            /* Save SceneManager object reference */
            this.sceneManager = sceneManager;

            /* Save GraphicsComponent object reference */
            graphics = graphicsComponent;

            /* Initialize the properties of the tiles and spritesheet */
            twoDimensionalSheet = tileSheet;
            currentSheet = tileSheet;
            gridWidth = numXTiles;
            gridHeight = numYTiles;
            cellWidth = tileWidth;
            cellHeight = tileHeight;
            worldOffset = offset;

            /* Set the visible zone of the tile set */
            visibleTiles = new Rectangle(0, 0, gridWidth, gridHeight);

            /* Initialize the grid to the size of 'gridWidth' and 'gridHeight' */
            grid = new int[gridWidth][];
            for (int i = 0; i < gridWidth; i++)
            {
                grid[i] = new int[gridHeight];
                for (int j = 0; j < gridHeight; j++)
                {
                    grid[i][j] = 0;
                }
            }
       
        }

        /// <summary>
        /// Returns the Vector2 position based on the parameter position
        /// </summary>
        /// <param name="position"></param>
        /// <returns></returns>
        public Vector2 onTile(Vector2 position)
        {
            Vector2 tilePos = new Vector2(
                (int)(position.X / cellWidth),
                (int)(position.Y / cellHeight));

            return tilePos;
        }

        /// <summary>
        /// Updates grid tile value at the specified position
        /// </summary>
        /// <param name="position">Position as vector 2</param>
        /// <param name="tileValue">Tile value as integer</param>
        public void SetTile(Vector2 position, int tileValue)
        {
            if (position.X < gridWidth &&
                position.X >= 0 &&
                position.Y < gridHeight &&
                position.Y >= 0)
            {
                grid[(int)position.X][(int)position.Y] = tileValue;
            }
            else
            {
                // throw new Exception("Invalid grid position to set tile!");
            }
        }


        /// <summary>
        /// Sets the tile for the given x and y index value
        /// </summary>
        /// <param name="xIndex">x index as int</param>
        /// <param name="yIndex">y index as int</param>
        /// <param name="tile">tile sprite as int</param>
        public void SetTile(int xIndex, int yIndex, int tile)
        {
            grid[xIndex][yIndex] = tile;
        }

        
        public void useAlternateSpriteSheet()
        {
            currentSheet = isometricSheet;
        }

        public void useMainSpriteSheet()
        {
            currentSheet = twoDimensionalSheet;
        }


        public void DrawTile(Vector2 gridPosition)
        {
            Vector2 position = new Vector2();
            position = Vector2.Zero;
            int x = (int)gridPosition.X;
            int y = (int)gridPosition.Y;

            Rectangle sourceRect = new Rectangle();
            if (grid[x][y] != 0){
            /* determine the spriesheet graphic based on grid position */
            currentSheet.GetRectangle(ref grid[x][y], out sourceRect);

            sceneManager.rampart.spriteBatch.Draw(
                 currentSheet.Texture,
                           new Vector2(cellWidth * x, (cellHeight * y) - (sourceRect.Height - cellHeight)),
                           sourceRect,
                           layerColor);
                        //rotationValue, position, 1, SpriteEffects.None, 0.0f);
             }
         }


        public void Update(GameTime gameTime)
        {
            foreach (AnimatedTile animatedTile in animatedTiles.Values)
            {
                animatedTile.Update(gameTime);
            }
        }

        /// <summary>
        /// Draws the grid tileset to the scene manager */
        /// </summary>
        public void Draw()
        {
            Vector2 position = new Vector2();
            position = Vector2.Zero;
           
            Rectangle sourceRect = new Rectangle();
            for (int x = 0; x < gridWidth ; x++)
            {
                for (int y = 0; y < gridHeight; y++)
                {
                    if (grid[x][y] != 0)
                    {
                        
                        // Should we draw an animated tile?
                        if (animatedTiles.ContainsKey(grid[x][y]))
                        {
                            AnimatedTile animatedTile = animatedTiles[grid[x][y]];
                            animatedTile.Draw(cellWidth * x, cellHeight * y, sceneManager.rampart.spriteBatch);

                        } else 
                        {
                            /* determine the spriesheet graphic based on grid position */
                            currentSheet.GetRectangle(ref grid[x][y], out sourceRect);
                            
                            /* draw the tile */
                            sceneManager.rampart.spriteBatch.Draw(
                                currentSheet.Texture,
                                new Vector2(cellWidth * x, (cellHeight * y) - (sourceRect.Height - cellHeight)),
                                sourceRect,
                                layerColor);
                        }
                    }
                }
            }            
        }
        #endregion        
        
    }
}

